/**
 * <p>文件名:	HessianProxyServiceFactoryBean.java</p>
 * <p>版权:		CopyrightTag</p>
 * <p>公司:		CompanyTag</p>
 * @author		郭训常(guoxunchang@ctfo.com)
 */
package com.caits.lbs.framework.services.hessian.client.session;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.ClassUtils;

import com.caits.lbs.framework.log.CommonLogFactory;
import com.caucho.hessian.client.HessianProxyFactory;

/**
 * <p>
 * HessianProxyServiceFactoryBean.java
 * </p>
 * <p>
 * 支持多个服务的hessian rmi调用，按照响应时间最短优先级调用
 * </p>
 * 
 * @author <a href="mailto:guoxunchang@ctfo.com">郭训常</a>
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th><th width="100px">动作</th><th
 *          width="100px">修改人</th><th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>郭训常</td>
 *          <td>2011-3-24 下午04:29:25</td>
 *          </tr>
 *          </table>
 */
public class HessianProxyServiceFactoryBean implements FactoryBean, InitializingBean {
	/** 日志记录类 */
	private Logger log = CommonLogFactory.getLog();
	
	private Object serviceProxy;
	
	/** 远程调用服务的列表 */
	private List<SessionHessianProxy> services = new ArrayList<SessionHessianProxy>();
	/** 服务地址列表 */
	private List<String> serviceUrls;
	/***各个服务的状态 key：下标，value：>=0 耗时 ms, Long.MAX_VALUE,不通 or 未尝试*/
	private Map<Integer, Long> serviceStatus = new HashMap<Integer, Long>();
	
	private Class<?> serviceInterface;
	
	public void setServiceInterface(Class<?> serviceInterface) {
		if (serviceInterface != null && !serviceInterface.isInterface()) {
			throw new IllegalArgumentException("'serviceInterface' must be an interface");
		}
		this.serviceInterface = serviceInterface;
	}

	/**
	 * Return the interface of the service to access.
	 */
	public Class<?> getServiceInterface() {
		return this.serviceInterface;
	}

	/**
	 * @param serviceUrls the serviceUrls to set
	 */
	public void setServiceUrls(List<String> serviceUrls) {
		this.serviceUrls = serviceUrls;
		for(int i = 0; i < serviceUrls.size(); i ++){
			serviceStatus.put(i, Long.MAX_VALUE);
		}
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	public Object getObject() throws Exception {
		return serviceProxy;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#getObjectType()
	 */
	public Class<?> getObjectType() {
		return serviceInterface;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.FactoryBean#isSingleton()
	 */
	public boolean isSingleton() {
		return true;
	}

	/**
	 * 获取变量serviceUrls的值
	 * @return the serviceUrls 数据类型 : List<String>
	 */
	public List<String> getServiceUrls() {
		return serviceUrls;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
		if(beanClassLoader == null){
			beanClassLoader = this.getClass().getClassLoader();
		}
		for(String serviceUrl : serviceUrls){
			if(serviceUrl != null && serviceUrl.trim().length() > 0){
				SessionHessianProxy handler = new SessionHessianProxy(new URL(serviceUrl), new HessianProxyFactory());
				services.add(handler);
			}
		}
		this.serviceProxy = Proxy.newProxyInstance(beanClassLoader, new Class[] { getServiceInterface() }, new InvocationHandler() {
			
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				String methodName = method.getName();
				if (methodName.equals("equals")) {
					return method.invoke(proxy, args);
				} else if (methodName.equals("hashCode"))
					return method.invoke(proxy, args);
				else if (methodName.equals("toString"))
					return "HessianProxyServiceFactoryBean[" + serviceUrls + "]";
				Object ren = null;
				//计算调用顺序列表，响应时间最短的排前
				List<Integer> callSeqArr = calculateGoodest(serviceStatus);
				for(int idx : callSeqArr){
					SessionHessianProxy service = services.get(idx);
					try{
						long start = System.currentTimeMillis();
						ren = service.invoke(proxy, method, args);
						long costtime = System.currentTimeMillis() - start;
						serviceStatus.put(idx, costtime);
					}catch (Exception e) {
						log.error(e);
						serviceStatus.put(idx, Long.MAX_VALUE);
					}
					if(ren != null){//得到返回值跳出
						break;
					}
				}
//				if(ren == null){
//					ren = String.valueOf("没有可用的服务");
//				}
				return ren;
			}

			private List<Integer> calculateGoodest(final Map<Integer, Long> serviceStatus) {
				List<Integer> keyList = new ArrayList<Integer>(serviceStatus.keySet());
				if(keyList.size() <= 1){//无可比，直接返回
					return keyList;
				}
				Collections.sort(keyList, new Comparator<Integer>() {
					public int compare(Integer o1, Integer o2) {
						Long val1 = serviceStatus.get(o1);
						Long val2 = serviceStatus.get(o2);
						return val1.compareTo(val2);
					}
				});
				return keyList;
			}
			
		});
	}

}
